home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / sox / smp.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  8KB  |  307 lines

  1. /*
  2.  * June 30, 1992
  3.  * Copyright 1992 Leigh Smith And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Leigh Smith And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * Sound Tools SampleVision file format driver.
  12.  * Output is always in little-endian (80x86/VAX) order.
  13.  * 
  14.  * Derived from: Sound Tools skeleton handler file.
  15.  */
  16.  
  17. #include "st.h"
  18. #ifndef __STDC__
  19. #include <string.h>
  20. #endif
  21.  
  22. #define NAMELEN    30        /* Size of Samplevision name */
  23. #define COMMENTLEN 60        /* Size of Samplevision comment, not shared */
  24. #define MIDI_UNITY 60        /* MIDI note number to play sample at unity */
  25.  
  26. /* The header preceeding the sample data */
  27. struct smpheader {
  28.     char Id[18];        /* File identifier */
  29.     char version[4];    /* File version */
  30.     char comments[COMMENTLEN];    /* User comments */
  31.     char name[NAMELEN + 1];    /* Sample Name, left justified */
  32. };
  33. #define HEADERSIZE (sizeof(struct smpheader) - 1)    /* -1 for name's \0 */
  34.  
  35. /* Samplevision loop definition structure */
  36. struct loop {
  37.     unsigned long start; /* Sample count into sample data, not byte count */
  38.     unsigned long end;   /* end point */
  39.     char type;         /* 0 = loop off, 1 = forward, 2 = forw/back */
  40.     short count;         /* No of times to loop */
  41. };
  42.  
  43. /* Samplevision marker definition structure */
  44. struct marker {
  45.     char name[10];        /* Ascii Marker name */
  46.     unsigned long position;    /* Sample Number, not byte number */
  47. };
  48.  
  49. /* The trailer following the sample data */
  50. struct smptrailer {
  51.     struct loop loops[8];        /* loops */
  52.     struct marker markers[8];    /* markers */
  53.     char MIDInote;            /* for unity pitch playback */
  54.     unsigned long rate;        /* in hertz */
  55.     unsigned long SMPTEoffset;    /* in subframes */
  56.     unsigned long CycleSize;    /* sample count in one cycle of the */
  57.                     /* sampled sound -1 if unknown */
  58. };
  59.  
  60. /* Private data for SMP file */
  61. typedef struct smpstuff {
  62.     unsigned long NoOfSamps;    /* Sample data count in words */
  63.     char comment[NAMELEN + 1];    /* comment memory resides in private */
  64. } *smp_t;                /* data because it's small */
  65.  
  66. char *SVmagic = "SOUND SAMPLE DATA ", *SVvers = "2.1 ";
  67.  
  68. IMPORT float volume, amplitude;
  69. IMPORT int summary, verbose;
  70.  
  71. /*
  72.  * Read the SampleVision trailer structure.
  73.  * Returns 1 if everything was read ok, 0 if there was an error.
  74.  */
  75. static int readtrailer(ft, trailer)
  76. ft_t ft;
  77. struct smptrailer *trailer;
  78. {
  79.     int i;
  80.  
  81.     rlshort(ft);            /* read reserved word */
  82.     for(i = 0; i < 8; i++) {    /* read the 8 loops */
  83.         trailer->loops[i].start = rllong(ft);
  84.         trailer->loops[i].end = rllong(ft);
  85.         trailer->loops[i].type = getc(ft->fp);
  86.         trailer->loops[i].count = rlshort(ft);
  87.     }
  88.     for(i = 0; i < 8; i++) {    /* read the 8 markers */
  89.         if (fread(trailer->markers[i].name, 1, 10, ft->fp) != 10)
  90.             return(0);
  91.         trailer->markers[i].position = rllong(ft);
  92.     }
  93.     trailer->MIDInote = getc(ft->fp);
  94.     trailer->rate = rllong(ft);
  95.     trailer->SMPTEoffset = rllong(ft);
  96.     trailer->CycleSize = rllong(ft);
  97.     return(1);
  98. }
  99.  
  100. /*
  101.  * set the trailer data - loops and markers, to reasonably benign values
  102.  */
  103. static settrailer(trailer, rate)
  104. struct smptrailer *trailer;
  105. unsigned int rate;
  106. {
  107.     int i;
  108.  
  109.     trailer->loops[0].start = ~0;    /* set first loop start as FFFFFFFF */
  110.     trailer->loops[0].end = 0;    /* to mark it as not set */
  111.     trailer->loops[0].type = 0;
  112.     trailer->loops[0].count = 0;
  113.     for(i = 1; i < 8; i++) {    /* assign the 7 other loops */
  114.         trailer->loops[i].start = 0;
  115.         trailer->loops[i].end = 0;
  116.         trailer->loops[i].type = 0;
  117.         trailer->loops[i].count = 0;
  118.     }
  119.     for(i = 0; i < 8; i++) {    /* write the 8 markers */
  120.         strcpy(trailer->markers[i].name, "          ");
  121.         trailer->markers[i].position = ~0;
  122.     }
  123.     trailer->MIDInote = MIDI_UNITY;        /* Unity play back */
  124.     trailer->rate = rate;
  125.     trailer->SMPTEoffset = 0;
  126.     trailer->CycleSize = -1;
  127. }
  128.  
  129. /*
  130.  * Write the SampleVision trailer structure.
  131.  * Returns 1 if everything was written ok, 0 if there was an error.
  132.  */
  133. static int writetrailer(ft, trailer)
  134. ft_t ft;
  135. struct smptrailer *trailer;
  136. {
  137.     int i;
  138.  
  139.     wlshort(ft, 0);            /* write the reserved word */
  140.     for(i = 0; i < 8; i++) {    /* write the 8 loops */
  141.         wllong(ft, trailer->loops[i].start);
  142.         wllong(ft, trailer->loops[i].end);
  143.         putc(trailer->loops[i].type, ft->fp);
  144.         wlshort(ft, trailer->loops[i].count);
  145.     }
  146.     for(i = 0; i < 8; i++) {    /* write the 8 markers */
  147.         if (fwrite(trailer->markers[i].name, 1, 10, ft->fp) != 10)
  148.             return(0);
  149.         wllong(ft, trailer->markers[i].position);
  150.     }
  151.     putc(trailer->MIDInote, ft->fp);
  152.     wllong(ft, trailer->rate);
  153.     wllong(ft, trailer->SMPTEoffset);
  154.     wllong(ft, trailer->CycleSize);
  155.     return(1);
  156. }
  157.  
  158. /*
  159.  * Do anything required before you start reading samples.
  160.  * Read file header. 
  161.  *    Find out sampling rate, 
  162.  *    size and style of samples, 
  163.  *    mono/stereo/quad.
  164.  */
  165. smpstartread(ft) 
  166. ft_t ft;
  167. {
  168.     smp_t smp = (smp_t) ft->priv;
  169.     int littlendian = 0, i;
  170.     long samplestart;
  171.     char *endptr;
  172.     struct smpheader header;
  173.     struct smptrailer trailer;
  174.  
  175.     /* If you need to seek around the input file. */
  176.     if (! ft->seekable)
  177.         fail("SMP input file must be a file, not a pipe");
  178.  
  179.     /* Read SampleVision header */
  180.     if (fread((char *) &header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
  181.         fail("unexpected EOF in SMP header");
  182.     if (strncmp(header.Id, SVmagic, 17) != 0)
  183.         fail("SMP header does not begin with magic word %s\n", SVmagic);
  184.     if (strncmp(header.version, SVvers, 4) != 0)
  185.         fail("SMP header is not version %s\n", SVvers);
  186.  
  187.     strncpy(smp->comment, header.name, NAMELEN);
  188.         for (i = NAMELEN; i >= 0 && smp->comment[i] == ' '; i--)
  189.         smp->comment[i] = '\0';
  190.     ft->comment = smp->comment;
  191.     report("SampleVision File name: %s", ft->comment);
  192.     report("File comments: %.*s", COMMENTLEN, header.comments);
  193.     /* Extract out the sample size (always intel format) */
  194.     smp->NoOfSamps = rllong(ft);
  195.     /* mark the start of the sample data */
  196.     samplestart = ftell(ft->fp);
  197.  
  198.     /* seek from the current position (the start of sample data) by */
  199.     /* NoOfSamps * 2 */
  200.     if (fseek(ft->fp, smp->NoOfSamps * 2L, 1) == -1)
  201.         fail("SMP unable to seek to trailer");
  202.     if (!readtrailer(ft, &trailer))
  203.         fail("unexpected EOF in SMP trailer");
  204.  
  205.     /* seek back to the beginning of the data */
  206.     if (fseek(ft->fp, samplestart, 0) == -1) 
  207.         fail("SMP unable to seek back to start of sample data");
  208.  
  209.     ft->info.rate = (int) trailer.rate;
  210.     ft->info.size = WORD;
  211.     ft->info.style = SIGN2;
  212.     ft->info.channels = 1;
  213.  
  214.     endptr = (char *) &littlendian;
  215.     *endptr = 1;
  216.     if (littlendian != 1)
  217.         ft->swap = 1;
  218. }
  219.  
  220. /*
  221.  * Read up to len samples from file.
  222.  * Convert to signed longs.
  223.  * Place in buf[].
  224.  * Return number of samples read.
  225.  */
  226. smpread(ft, buf, len) 
  227. ft_t ft;
  228. long *buf, len;
  229. {
  230.     smp_t smp = (smp_t) ft->priv;
  231.     register long datum;
  232.     int done = 0;
  233.     
  234.     for(; done < len && smp->NoOfSamps; done++, smp->NoOfSamps--) {
  235.         datum = rshort(ft);
  236.         /* scale signed up to long's range */
  237.         *buf++ = LEFT(datum, 16);
  238.     }
  239.     return done;
  240. }
  241.  
  242. /*
  243.  * Do anything required when you stop reading samples.  
  244.  * Don't close input file! 
  245.  */
  246. smpstopread(ft) 
  247. ft_t ft;
  248. {
  249. }
  250.  
  251. smpstartwrite(ft) 
  252. ft_t ft;
  253. {
  254.     smp_t smp = (smp_t) ft->priv;
  255.     struct smpheader header;
  256.  
  257.     /* If you have to seek around the output file */
  258.     if (! ft->seekable)
  259.         fail("Output .smp file must be a file, not a pipe");
  260.  
  261.     /* If your format specifies any of the following info. */
  262.     ft->info.size = WORD;
  263.     ft->info.style = SIGN2;
  264.     ft->info.channels = 1;
  265.  
  266.     strcpy(header.Id, SVmagic);
  267.     strcpy(header.version, SVvers);
  268.     sprintf(header.comments, "%-*s", COMMENTLEN, "Converted using Sox.");
  269.     sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, ft->comment);
  270.  
  271.     /* Write file header */
  272.     if(fwrite(&header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
  273.         fail("SMP: Can't write header completely");
  274.     wllong(ft, 0);    /* write as zero length for now, update later */
  275.     smp->NoOfSamps = 0;
  276. }
  277.  
  278. smpwrite(ft, buf, len) 
  279. ft_t ft;
  280. long *buf, len;
  281. {
  282.     smp_t smp = (smp_t) ft->priv;
  283.     register int datum;
  284.  
  285.     while(len--) {
  286.         datum = RIGHT(*buf++, 16);
  287.         wlshort(ft, datum);
  288.         smp->NoOfSamps++;
  289.     }
  290.     /* If you cannot write out all of the supplied samples, */
  291.     /*    fail("SMP: Can't write all samples to %s", ft->filename); */
  292. }
  293.  
  294. smpstopwrite(ft) 
  295. ft_t ft;
  296. {
  297.     smp_t smp = (smp_t) ft->priv;
  298.     struct smptrailer trailer;
  299.  
  300.     /* Assign the trailer data */
  301.     settrailer(&trailer, ft->info.rate);
  302.     writetrailer(ft, &trailer);
  303.     if (fseek(ft->fp, 112, 0) == -1)
  304.         fail("SMP unable to seek back to save size");
  305.     wllong(ft, smp->NoOfSamps);
  306. }
  307.